#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
视频下载工具
专门用于爬取和下载视频文件
"""

import os
import sys
import argparse
import time
from datetime import datetime

# 将项目根目录添加到Python搜索路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config import settings
from crawler import MusicCrawler
from utils import setup_logger, write_log_to_file, format_file_size
from src.downloader import MusicDownloader

logger = setup_logger('video_downloader')

class VideoDownloader:
    """视频下载类，专门用于处理视频的爬取和下载"""
    def __init__(self):
        self.crawler = MusicCrawler()
        self.music_downloader = MusicDownloader()
        # 视频保存路径，默认在音乐保存路径下创建videos子目录
        self.video_save_path = os.path.join(settings.MUSIC_SAVE_PATH, 'videos')
        
        # 确保视频保存目录存在
        from utils import create_dir_if_not_exists
        create_dir_if_not_exists(self.video_save_path)
    
    def find_video_categories(self):
        """查找网站上的视频分类链接
        
        Returns:
            list: 视频分类链接列表，每个元素是(分类名称, 分类URL)的元组
        """
        logger.info("开始查找视频分类链接...")
        
        # 尝试获取首页内容
        homepage_content = None
        try:
            # 首先尝试使用Selenium获取首页
            logger.info("尝试使用Selenium获取首页...")
            homepage_content = self.crawler.get_page(self.crawler.base_url, use_selenium=True)
        except Exception as e:
            logger.warning(f"Selenium获取首页失败: {e}")
        
        # 如果Selenium失败，尝试使用requests直接获取
        if not homepage_content:
            try:
                import requests
                from bs4 import BeautifulSoup
                from urllib.parse import urljoin
                
                logger.info("尝试使用requests获取首页...")
                response = requests.get(self.crawler.base_url, timeout=30)
                response.raise_for_status()
                response.encoding = response.apparent_encoding
                homepage_content = response.text
            except Exception as e:
                logger.error(f"获取首页失败: {e}")
                return []
        
        try:
            from bs4 import BeautifulSoup
            from urllib.parse import urljoin
            
            soup = BeautifulSoup(homepage_content, 'html.parser')
            video_categories = []
            
            # 查找所有链接，寻找包含'video'或'视频'的链接
            logger.info("查找包含'video'或'视频'关键词的链接")
            
            # 先尝试使用分类容器选择器
            category_container = soup.select_one('.ilingku_fl')
            
            if category_container:
                logger.info("找到分类容器，查找视频相关分类")
                category_links = category_container.find_all('a')
                
                for link in category_links:
                    href = link.get('href', '')
                    text = link.get_text().strip()
                    
                    # 检查链接或文本是否包含视频相关关键词
                    if 'video' in href.lower() or '视频' in text:
                        full_url = urljoin(self.crawler.base_url, href)
                        video_categories.append((text, full_url))
                        logger.info(f"找到视频分类: {text} - {full_url}")
            
            # 如果在分类容器中没找到，查找页面中所有包含视频关键词的链接
            if not video_categories:
                logger.info("在全页面查找视频相关链接")
                all_links = soup.find_all('a')
                
                for link in all_links:
                    href = link.get('href', '')
                    text = link.get_text().strip()
                    title = link.get('title', '')
                    
                    # 检查链接或文本是否包含视频相关关键词
                    if ('video' in href.lower() or '视频' in text or 'video' in title.lower() or 'mv' in href.lower() or 'MV' in text):
                        full_url = urljoin(self.crawler.base_url, href)
                        # 避免重复添加相同的URL
                        if not any(url == full_url for _, url in video_categories):
                            video_categories.append((text, full_url))
                            logger.info(f"找到视频相关链接: {text} - {full_url}")
            
            logger.info(f"总共找到 {len(video_categories)} 个视频相关链接")
            return video_categories
        except Exception as e:
            logger.error(f"查找视频分类失败: {e}")
            return []
    
    def crawl_video_category(self, category_url, max_pages=5):
        """爬取指定视频分类的所有视频信息
        
        Args:
            category_url: 视频分类URL
            max_pages: 最大爬取页数
            
        Returns:
            int: 爬取的视频数量
        """
        logger.info(f"开始爬取视频分类: {category_url}, 最大页数: {max_pages}")
        write_log_to_file(f"开始爬取视频分类: {category_url}, 最大页数: {max_pages}", "INFO")
        
        try:
            # 使用crawler的crawl_video_category方法爬取视频分类
            total_videos = self.crawler.crawl_video_category(category_url, max_pages)
            
            logger.info(f"视频分类爬取完成，共获取 {total_videos} 个视频信息")
            write_log_to_file(f"视频分类爬取完成，共获取 {total_videos} 个视频信息", "INFO")
            return total_videos
        except Exception as e:
            logger.error(f"爬取视频分类失败: {e}")
            write_log_to_file(f"爬取视频分类失败: {e}", "ERROR")
            return 0
    
    def download_videos(self, limit=100, artist_dir=True):
        """下载待处理的视频文件
        
        Args:
            limit: 最大下载数量
            artist_dir: 是否按歌手分类保存
            
        Returns:
            tuple: (成功数量, 失败数量)
        """
        logger.info(f"开始下载视频文件，限制数量: {limit}")
        write_log_to_file(f"开始下载视频文件，限制数量: {limit}", "INFO")
        
        try:
            # 获取待处理的视频
            pending_videos = self.crawler.db_manager.get_pending_videos(limit)
            
            if not pending_videos:
                logger.info("没有待下载的视频")
                return 0, 0
            
            logger.info(f"找到 {len(pending_videos)} 个待下载的视频")
            
            # 准备下载的视频数据
            videos_to_download = []
            for video in pending_videos:
                # 确保video对象包含必要的信息
                if 'url' not in video or not video['url']:
                    logger.warning(f"视频缺少下载链接: {video.get('title', '未知视频')}")
                    continue
                
                # 添加媒体类型标识
                video['media_type'] = 'video'
                videos_to_download.append(video)
            
            if not videos_to_download:
                logger.info("没有有效的视频下载链接")
                return 0, 0
            
            # 修改MusicDownloader的保存路径为视频保存路径
            original_save_path = self.music_downloader.save_path
            self.music_downloader.save_path = self.video_save_path
            
            success_count = 0
            failed_count = 0
            total_size = 0
            
            # 逐个下载视频
            for video in videos_to_download:
                success, file_path, file_size = self._download_single_video(video, artist_dir)
                
                if success:
                    success_count += 1
                    total_size += file_size
                    # 更新视频状态为downloaded
                    self.crawler.db_manager.update_video_status(
                        video['video_id'], 
                        'downloaded',
                        file_path=file_path,
                        file_size=file_size
                    )
                else:
                    failed_count += 1
                    # 更新视频状态为failed
                    self.crawler.db_manager.update_video_status(video['video_id'], 'failed')
            
            # 恢复MusicDownloader的原始保存路径
            self.music_downloader.save_path = original_save_path
            
            logger.info(f"视频下载完成: 成功 {success_count} 个, 失败 {failed_count} 个")
            logger.info(f"下载总大小: {format_file_size(total_size)}")
            
            write_log_to_file(
                f"视频下载完成: 成功 {success_count} 个, 失败 {failed_count} 个, 总大小: {format_file_size(total_size)}", 
                "INFO"
            )
            
            return success_count, failed_count
        except Exception as e:
            logger.error(f"下载视频失败: {e}")
            write_log_to_file(f"下载视频失败: {e}", "ERROR")
            return 0, 0
    
    def _download_single_video(self, video, artist_dir=True):
        """下载单个视频文件
        
        Args:
            video: 视频数据
            artist_dir: 是否按歌手分类保存
            
        Returns:
            tuple: (是否成功, 文件路径, 文件大小)
        """
        try:
            title = video.get('title', '未知视频')
            artist = video.get('artist', '未知歌手')
            url = video.get('url', '')
            
            if not url:
                logger.error(f"没有找到下载链接: {title} - {artist}")
                return False, None, 0
            
            # 构建保存路径
            save_dir = self.video_save_path
            
            # 按歌手分类
            if artist_dir:
                from utils import clean_filename
                artist = clean_filename(artist)
                save_dir = os.path.join(save_dir, artist)
            
            # 从URL中提取文件扩展名
            # 先处理URL参数，获取主URL部分
            main_url = url.split('?')[0].lower()
            
            # 使用字符串处理方法提取扩展名
            last_dot_index = main_url.rfind('.')
            if last_dot_index != -1 and last_dot_index < len(main_url) - 1:
                url_ext = main_url[last_dot_index:]
                # 确保扩展名合理，不超过5个字符
                if len(url_ext) > 5:
                    url_ext = '.mp4'
            else:
                # 没有找到有效扩展名，使用默认值
                url_ext = '.mp4'
            
            # 构建文件名
            from utils import clean_filename
            filename = clean_filename(f"{title} - {artist}{url_ext}")
            file_path = os.path.join(save_dir, filename)
            
            # 下载文件
            success, file_path, file_size = self.music_downloader.download_file(url, file_path)
            
            return success, file_path, file_size
        except Exception as e:
            logger.error(f"下载视频失败: {video.get('title', '未知视频')}, 错误: {e}")
            return False, None, 0
    
    def process_pending_videos(self, limit=100):
        """处理数据库中状态为pending的视频对象，获取详细信息
        
        Args:
            limit: 最大处理数量
            
        Returns:
            int: 处理的视频数量
        """
        logger.info(f"开始处理待处理的视频对象，限制数量: {limit}")
        write_log_to_file(f"开始处理待处理的视频对象，限制数量: {limit}", "INFO")
        
        try:
            # 使用crawler的process_pending_media方法，指定media_type为video
            processed_count = self.crawler.process_pending_media(media_type='video', limit=limit)
            
            logger.info(f"视频处理完成，共处理 {processed_count} 个视频对象")
            write_log_to_file(f"视频处理完成，共处理 {processed_count} 个视频对象", "INFO")
            return processed_count
        except Exception as e:
            logger.error(f"处理视频对象失败: {e}")
            write_log_to_file(f"处理视频对象失败: {e}", "ERROR")
            return 0
    
    def close(self):
        """关闭资源"""
        if hasattr(self, 'crawler'):
            self.crawler.close()


def parse_arguments():
    """解析命令行参数"""
    parser = argparse.ArgumentParser(description='视频下载工具')
    
    # 子命令
    subparsers = parser.add_subparsers(dest='command', help='可用命令')
    
    # 查找视频分类命令
    find_parser = subparsers.add_parser('find', help='查找视频分类链接')
    
    # 爬取视频命令
    crawl_parser = subparsers.add_parser('crawl', help='爬取视频信息')
    crawl_parser.add_argument('--category', type=str, help='爬取指定分类URL')
    crawl_parser.add_argument('--max-pages', type=int, default=5, help='最大爬取页数')
    
    # 处理视频命令
    process_parser = subparsers.add_parser('process', help='处理待处理的视频对象')
    process_parser.add_argument('--limit', type=int, default=100, help='处理视频数量限制')
    
    # 下载视频命令
    download_parser = subparsers.add_parser('download', help='下载视频')
    download_parser.add_argument('--limit', type=int, default=100, help='下载视频数量限制')
    download_parser.add_argument('--artist-dir', action='store_true', default=True, help='按歌手分类保存')
    
    # 完整流程命令
    full_parser = subparsers.add_parser('full', help='执行完整的视频爬取和下载流程')
    full_parser.add_argument('--category', type=str, help='爬取指定分类URL')
    full_parser.add_argument('--max-pages', type=int, default=5, help='最大爬取页数')
    full_parser.add_argument('--limit', type=int, default=100, help='下载视频数量限制')
    
    return parser.parse_args()

def main():
    """主函数"""
    print("\n===== 视频下载工具 =====\n")
    
    # 解析命令行参数
    args = parse_arguments()
    
    if not args.command:
        print("请指定命令，使用 -h 查看帮助")
        return
    
    # 创建视频下载器实例
    video_downloader = VideoDownloader()
    
    try:
        if args.command == 'find':
            # 查找视频分类
            print("正在查找视频分类链接...")
            video_categories = video_downloader.find_video_categories()
            
            if video_categories:
                print(f"\n找到 {len(video_categories)} 个视频分类:")
                for i, (text, url) in enumerate(video_categories, 1):
                    print(f"{i}. {text}: {url}")
                print("\n请使用以上URL进行视频爬取")
            else:
                print("未找到视频分类链接")
        elif args.command == 'crawl':
            # 爬取视频信息
            if not args.category:
                print("请指定视频分类URL，使用 -h 查看帮助")
                return
            
            video_downloader.crawl_video_category(args.category, args.max_pages)
        elif args.command == 'process':
            # 处理待处理的视频对象
            video_downloader.process_pending_videos(args.limit)
        elif args.command == 'download':
            # 下载视频
            success, failed = video_downloader.download_videos(args.limit, args.artist_dir)
            print(f"\n下载完成: 成功 {success} 个, 失败 {failed} 个")
        elif args.command == 'full':
            # 执行完整流程
            if not args.category:
                print("请指定视频分类URL，使用 -h 查看帮助")
                return
            
            # 1. 爬取视频信息
            print("1. 开始爬取视频分类...")
            video_downloader.crawl_video_category(args.category, args.max_pages)
            
            # 2. 处理待处理的视频对象
            print("\n2. 开始处理视频对象...")
            video_downloader.process_pending_videos(args.limit)
            
            # 3. 下载视频
            print("\n3. 开始下载视频...")
            success, failed = video_downloader.download_videos(args.limit)
            
            print(f"\n完整流程完成: 成功下载 {success} 个视频, 失败 {failed} 个视频")
        else:
            print(f"未知命令: {args.command}")
            print("使用帮助: python download_videos.py -h")
    finally:
        # 关闭资源
        video_downloader.close()

if __name__ == '__main__':
    try:
        main()
    except KeyboardInterrupt:
        logger.info("程序被用户中断")
        write_log_to_file("程序被用户中断", "INFO")
    except Exception as e:
        logger.error(f"程序运行出错: {e}")
        write_log_to_file(f"程序运行出错: {e}", "ERROR")
        sys.exit(1)